﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using HYCodeBase.Math;
using HYRevitCode.XYZUtility;

namespace HYRevitCode.BoundingBoxUtility
{
	public class BoundingBoxUtilityMethod
	{
		public static BoundingBoxUV CalculateBoundingBox2D(XYZ ptStart, XYZ ptEnd)
		{
			double x = ptStart.X;
			double x2 = ptEnd.X;
			double y = ptStart.Y;
			double y2 = ptEnd.Y;
			if (x > x2)
			{
				x = ptEnd.X;
				x2 = ptStart.X;
			}
			if (y > y2)
			{
				y = ptEnd.Y;
				y2 = ptStart.Y;
			}
			return new BoundingBoxUV(x, y, x2, y2);
		}

		public static BoundingBoxUV CalculateBoundingBox2D(XYZ ptStart, XYZ ptEnd, XYZ ptCenter, XYZ normal, double radius)
		{
			double num = ptStart.X;
			double num2 = ptEnd.X;
			double num3 = ptStart.Y;
			double num4 = ptEnd.Y;
			if (num > num2)
			{
				num = ptEnd.X;
				num2 = ptStart.X;
			}
			if (num3 > num4)
			{
				num3 = ptEnd.Y;
				num4 = ptStart.Y;
			}
			XYZ pt = ptCenter + XYZ.BasisX * radius;
			if (XYZUtilityMethod.Is_Point_OnSegment(ptStart, ptEnd, ptCenter, normal, pt, 1E-09))
			{
				num2 = ptCenter.X + radius;
			}
			XYZ pt2 = ptCenter - XYZ.BasisX * radius;
			if (XYZUtilityMethod.Is_Point_OnSegment(ptStart, ptEnd, ptCenter, normal, pt2, 1E-09))
			{
				num = ptCenter.X - radius;
			}
			XYZ pt3 = ptCenter + XYZ.BasisY * radius;
			if (XYZUtilityMethod.Is_Point_OnSegment(ptStart, ptEnd, ptCenter, normal, pt3, 1E-09))
			{
				num4 = ptCenter.Y + radius;
			}
			XYZ pt4 = ptCenter - XYZ.BasisY * radius;
			if (XYZUtilityMethod.Is_Point_OnSegment(ptStart, ptEnd, ptCenter, normal, pt4, 1E-09))
			{
				num3 = ptCenter.Y - radius;
			}
			return new BoundingBoxUV(num, num3, num2, num4);
		}

		public static BoundingBoxUV BoundingBoxesMerge(BoundingBoxUV box1, BoundingBoxUV box2)
		{
			BoundingBoxUV boundingBoxUV = new BoundingBoxUV();
			double u = box1.Min.U;
			double v = box1.Min.V;
			double u2 = box1.Max.U;
			double v2 = box1.Max.V;
			UV min = box2.Min;
			UV max = box2.Max;
			if (min.U < u)
			{
				u = min.U;
			}
			if (min.V < v)
			{
				v = min.V;
			}
			boundingBoxUV.Min = new UV(u, v);
			if (max.U > u2)
			{
				u2 = max.U;
			}
			if (max.V > v2)
			{
				v2 = max.V;
			}
			boundingBoxUV.Max = new UV(u2, v2);
			return boundingBoxUV;
		}

		public static BoundingBoxXYZ BoundingBoxesMerge(BoundingBoxXYZ box1, BoundingBoxXYZ box2)
		{
			BoundingBoxXYZ boundingBoxXYZ = new BoundingBoxXYZ();
			double x = box1.Min.X;
			double y = box1.Min.Y;
			double z = box1.Min.Z;
			double x2 = box1.Max.X;
			double y2 = box1.Max.Y;
			double z2 = box1.Max.Z;
			XYZ min = box2.Min;
			XYZ max = box2.Max;
			if (min.X < x)
			{
				x = min.X;
			}
			if (min.Y < y)
			{
				y = min.Y;
			}
			if (min.Z < z)
			{
				z = min.Z;
			}
			boundingBoxXYZ.Min = new XYZ(x, y, z);
			if (max.X > x2)
			{
				x2 = max.X;
			}
			if (max.Y > y2)
			{
				y2 = max.Y;
			}
			if (max.Z > z2)
			{
				z2 = max.Z;
			}
			boundingBoxXYZ.Max = new XYZ(x2, y2, z2);
			return boundingBoxXYZ;
		}

		public static BoundingBoxXYZ BoundingBoxesMerge(List<BoundingBoxXYZ> inputListBoundingBox)
		{
			if (inputListBoundingBox == null || inputListBoundingBox.Count < 1)
			{
				return null;
			}
			BoundingBoxXYZ boundingBoxXYZ = inputListBoundingBox[0];
			for (int i = 1; i < inputListBoundingBox.Count; i++)
			{
				boundingBoxXYZ = BoundingBoxUtilityMethod.BoundingBoxesMerge(boundingBoxXYZ, inputListBoundingBox[i]);
			}
			return boundingBoxXYZ;
		}

		public static BoundingBoxXYZ BoundingBox_Scale(BoundingBoxXYZ inputBoundingBox, double inputScal)
		{
			if (inputBoundingBox == null || MathUtility.Lessthan_Or_Equal(inputScal, 0.0))
			{
				return null;
			}
			XYZ min = inputBoundingBox.Min;
			XYZ max = inputBoundingBox.Max;
			XYZ xyz = (min + max) / 2.0;
			XYZ max2 = xyz + (max - xyz).Normalize() * (max.DistanceTo(xyz) * inputScal);
			XYZ min2 = xyz + (min - xyz).Normalize() * (min.DistanceTo(xyz) * inputScal);
			return new BoundingBoxXYZ
			{
				Max = max2,
				Min = min2
			};
		}

		public static BoundingBoxUV CalculateBoundingBox2D(Line line)
		{
			XYZ endPoint = line.GetEndPoint(0);
			XYZ endPoint2 = line.GetEndPoint(1);
			return BoundingBoxUtilityMethod.CalculateBoundingBox2D(endPoint, endPoint2);
		}

		public static BoundingBoxUV CalculateBoundingBox2D(Arc arc)
		{
			XYZ endPoint = arc.GetEndPoint(0);
			XYZ endPoint2 = arc.GetEndPoint(1);
			XYZ center = arc.Center;
			XYZ normal = arc.Normal;
			double radius = arc.Radius;
			if (arc.IsCyclic)
			{
				return new BoundingBoxUV(center.X - radius, center.Y - radius, center.X + radius, center.Y + radius);
			}
			return BoundingBoxUtilityMethod.CalculateBoundingBox2D(endPoint, endPoint2, center, normal, radius);
		}

		public static BoundingBoxUV CalculateBonundingBox2D(List<Curve> input)
		{
			BoundingBoxUV boundingBoxUV = null;
			foreach (Curve curve in input)
			{
				if (curve is Line || curve is Arc)
				{
					if (boundingBoxUV == null)
					{
						boundingBoxUV = ((curve is Line) ? BoundingBoxUtilityMethod.CalculateBoundingBox2D(curve as Line) : BoundingBoxUtilityMethod.CalculateBoundingBox2D(curve as Arc));
					}
					else
					{
						BoundingBoxUV box = (curve is Line) ? BoundingBoxUtilityMethod.CalculateBoundingBox2D(curve as Line) : BoundingBoxUtilityMethod.CalculateBoundingBox2D(curve as Arc);
						boundingBoxUV = BoundingBoxUtilityMethod.BoundingBoxesMerge(boundingBoxUV, box);
					}
				}
			}
			return boundingBoxUV;
		}
	}
}
